﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;
using csNotificaciones;

namespace MotorMetricas.Logica
{

    public class MetricaProfundidadArbolHerencia : AbstractMetrica
    {

        ArrayList ListaArbolesHerencia = new ArrayList(); // lista que contiene todos los arboles de herencia que se encuentren en el proyecto
        
        override public int Generar(String ruta)
        {

            ManejoArchivo Manejador = new ManejoArchivo();

            ArrayList misarchivos = new ArrayList();
            Boolean SinError = true;

            //Arbol ArbolHerencia = new Arbol(); // 

            if (Manejador.ValidarRuta(ruta))
            {

                misarchivos = Manejador.ObtenerArchivos(ruta);

            }
            else
            {
                SinError = false;
                //Console.WriteLine("ERROR: Ruta invalida");
            }

            if (SinError)
            {

                foreach (String rutaArchivo in misarchivos)
                {

                    string Hijo = ""; // string utilizado para cargar el nombre del hijo proveniente de ObtencionNodosArbolHerencia
                    string Padre = ""; // string utilizado para cargar el nombre del padre proveniente de ObtencionNodosArbolHerencia
                    Arbol ArbolAuxiliar = new Arbol(); // arbol auxiliar que me ayuda al proceso de insercion en un arbol ya existente
                    bool BanderaEnArbol = false; // usada para saber si existe alguien en los arboles de la lista
                    bool BanderaEnLista = false; // usada para verificar si se encuenta en la lista

                    if (Manejador.ValidarArchivo(rutaArchivo))
                    {

                        ObetencionNodosArbolHerencia(rutaArchivo, ref Hijo, ref Padre); // obtengo uno a uno la clase (hijo) con su respectiva superclase (padre), si este posee
                        
                        foreach (Arbol Actual in ListaArbolesHerencia) //recorro cada nodo de la lista de arboles
                        {
                            if (Actual.Contiene(Padre)) // Si el arbol contiene al padre, lo busco y al padre le agrego el hijo
                            {
                                Arbol ArbolInsercion = new Arbol(Hijo);
                                ArbolAuxiliar = Actual.DameArbol(Padre);
                                ArbolAuxiliar.Añade(ArbolInsercion);
                                BanderaEnArbol = true;
                            }
                        }

                        if (!BanderaEnArbol) // Si la bandera continua en falso es porque nunca encontro ese nodo en la lista de arboles, se agrega un elemento a la lista
                        {
                            foreach (Arbol Actual in ListaArbolesHerencia) //recorro cada nodo de la lista de arboles
                            {
                                if ( String.Compare(Hijo,Actual.Valor.ToString()) == 0) // busco si ya hay uno igual en la lista, si lo hay levanto la bandera
                                {
                                    BanderaEnLista = true;
                                }
                            }
                            if  (BanderaEnLista == false) // si no lo encuentro lo agrego a la lista, seria otro nodo raíz
                            {
                                Arbol ArbolInsercion = new Arbol();
                                if (Padre == "") // si el no tiene padre lo agrego a la lista
                                {
                                    ArbolInsercion = new Arbol(Hijo);
                                    ListaArbolesHerencia.Add(ArbolInsercion);
                                }
                                else // sino inserto el padre con su hijo agregado
                                {
                                    ArbolInsercion = new Arbol(Padre);
                                    ArbolAuxiliar = new Arbol(Hijo);
                                    ArbolInsercion.Añade(ArbolAuxiliar);
                                    ListaArbolesHerencia.Add(ArbolInsercion);
                                } 
                            }
                        }
                    }
                }
            }

            return (CalculoProfundidad( ListaArbolesHerencia ));
            
        }

        /*
         * Procedimiento que llevara un contador que, a medida que se recorra la lista, se preguntara si la altura del actual arbol
         * es mayor al contador entonces contador sera igual a la altura, sino se pasa al siguiente arbol en la lista,
         * de esta forma me quedara en contador la maxima altura de los arboles en lista.
         */ 
        public int CalculoProfundidad( ArrayList ListaArbolesHerencia )
        {
            int contador = 0;
            
            foreach ( Arbol Actual in ListaArbolesHerencia )
            {

                if (Actual.Alto > contador)
                {
                    contador = Actual.Alto;
                }

            }
            Notificacion.mostrarVentana("Metrica Profundidad Arbol de Herencia", "La metrica se ha generado con éxito\nResultado: " + contador.ToString(), Notificacion.Imagen.Ok, 2);
            return contador;
        }

        /*
         * Este procedimiento recibe un archivo para ser parseado y 2 strings por referencia que, cuando se encuentre la linea de codigo
         * en el que se encuentra la palabra "class" junto con ":", parte esa linea para obtener el nombre de la clase (hijo) y el
         * nombre de la superclase (padre) para ser retornado por medio de referencia.
         */
        static public void ObetencionNodosArbolHerencia( string rutaArchivo, ref string hijo, ref string padre )
        {
            string linea = null; // linea a ser parseada, sera asignada posteriormente
            string[] limitantes = new string[] { "class ", ":" } ; // limitantes para el split de la linea

            try
            {
                StreamReader archivo = new StreamReader(rutaArchivo);

                while ((linea = archivo.ReadLine()) != null)
                {
                    if (linea.Contains("class")) // si la linea contiene "class" entro
                    {
                        string[] postsplit = linea.Split(limitantes, StringSplitOptions.RemoveEmptyEntries); // hago el split con las limitantes
                        for (int contador = 0; contador < postsplit.Length; contador++) // deberia arrojarme un alista de 3 elementos que contiene las palabras PRE, el ENTRE y el POST de las limitantes
                        {
                            if (contador == 1) // si se da, esto quiere decir que estoy en el ENTRE, y esta es el nombre de la clase (hijo)
                                hijo = postsplit[contador];
                            if (contador == 2) // si se da, esto quiere decir que estoy en el POST, y esta es el nombre de la superclase (padre)
                                padre = postsplit[contador];
                        }
                    }
                }
                archivo.Close();

            }
            catch (Exception e)
            {
                Notificacion.mostrarVentana("Metrica Profundidad Arbol de Herencia", "Ha ocurrido un error al generar esta metrica", Notificacion.Imagen.Error, 1);
            }
        }
    }
}